8.8

waitdemo1-1.c

/* waitdemo1-1.c - shows how parent pause until child finishes
 *  creates two children and wait them quit.
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

#define DELAY 2

int main()
{
    int newpid, nnewpid;
    void child_code(int), parent_code(int,int);
    printf("before: mypid is %d\n", getpid());

    if ((newpid = fork()) == -1)
        perror("fork");
    else if (newpid == 0)
        child_code(DELAY);
    else{
        if ((nnewpid = fork()) == -1)
            perror("fork");
        else if (nnewpid == 0)
            child_code(DELAY);
        else
            parent_code(newpid, nnewpid);
    }
    return 0;
}

void child_code(int delay)
{
    printf("child %d here. will sleep for %d seconds \n", getpid(), delay);
    sleep(delay);
    printf("child done. about to exit\n");
    exit(17);
}

void parent_code(int childpid, int childpid2)
{
    int wait_rv, i;
    for (i = 0; i < 2; i++){
        wait_rv = wait(NULL);
        printf("done waiting for children,  Wait returned: %d\n", wait_rv);
    }
}
waitdemo1-2.c
/* waitdemo1-1.c - shows how parent pause until child finishes
 *  creates two children and wait them quit.
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/wait.h>

/* #define DELAY 2 */

int main(int argc, char **argv)
{

    int newpid, num, i;
    void child_code(int), parent_code(int);
    srand((unsigned)time(NULL));


    if (argc != 2){
        fprintf(stderr, "Usage: %s NUM\n", *argv);
        return 1;
    }else{
        num = atoi(argv[1]);
    }
    printf("before: mypid is %d\n", getpid());
    for (i = 0; i < num; i++){
        if ((newpid = fork()) == -1)
            perror("fork");
        else if (newpid == 0){
            child_code(rand() / 1000);
            break;
        }else{
            rand(); // 主进程调用, 不然子进程永远处在第一次调用.
        }
    }
    if (newpid != -1 && newpid != 0)
        parent_code(num);

    return 0;
}

void child_code(int delay)
{
    printf("child %d here. will sleep for %d micro seconds \n", getpid(), delay);
    usleep(delay);
    printf("child done. about to exit\n");
    exit(17);
}

void parent_code(int num)
{
    int wait_rv, i;
    for (i = 0; i < num; i++){
        wait_rv = wait(NULL);
        printf("done waiting for children,  Wait returned: %d\n", wait_rv);
    }
}

8.9

/* waitdemo2.c - shows how parent gets child status
 */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>

#define DELAY 5

int main()
{
    int newpid;
    void child_code(int);

    void chld_handler(int);
    signal(SIGCHLD, chld_handler);
    printf("before: mypid is %d\n", getpid());

    if ((newpid = fork()) == -1)
        perror("fork");
    else if (newpid == 0)
        child_code(DELAY);
    else
        while(1){
            printf("waiting...\n");
            sleep(1);
        }
    return 0;
}

void child_code(int delay)
{
    printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
    sleep(delay);
    printf("child done. about to exit\n");
    exit(17);
}

void chld_handler(int signum)
{
    int wait_rv;
    int child_status;
    int high_8, low_7, bit_7;

    wait_rv = wait(&child_status);

    printf("done waiting for child. Wait returned: %d\n", wait_rv);

    high_8 = child_status >> 8;  /* 1111 1111 0000 0000 */
    low_7 = child_status & 0x7F; /* 0000 0000 0111 1111 */
    bit_7 = child_status & 0x80; /* 0000 0000 0000 0000 */
    printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7);
    exit(0);
}

8.11 + 8.12

/* prompting shell version 2
 * Solves the 'one-shot' problem of version 1
 *  Uses execvp(), but fork()s first so that
 *  the shell waits around to perform another
 *  command
 * New problem: shell catches signals. Run vi, press ^C
 */
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>

#define MAXARGS 20
#define ARGLEN 100

void execute(char **);

int numargs;
int main()
{
    char *arglist[MAXARGS+1];
    char argbuf[ARGLEN];
    char *makestring();
    void int_handler(int);

    signal(SIGINT, int_handler);
    numargs = 0;
    while(numargs < MAXARGS)
    {
        printf("Arg[%d]? ", numargs);
        if (fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n')
            arglist[numargs++] = makestring(argbuf);
        else
        {
            if (numargs > 0){
                arglist[numargs] = NULL;
                execute(arglist);
                numargs = 0;
            }
        }
    }
    return 0;
}

void execute(char * arglist[])
{
    int pid, exitstatus;

    pid = fork();
    switch(pid){
        case -1:
            perror("fork failed");
            exit(1);
        case 0:
            execvp(arglist[0], arglist);
            perror("execvp failed");
            exit(1);
        default:
            while(wait(&exitstatus) != pid)
                ;
            printf("child exited with status %d, %d\n",
                    exitstatus >> 8, exitstatus & 0x7F);
    }
}

char *makestring(char *buf)
{
    char *cp;
    buf[strlen(buf) - 1] = '\0';
    cp = malloc(strlen(buf) + 1);
    if (cp == NULL){
        fprintf(stderr, "no memory\n");
        exit(1);
    }
    strcpy(cp, buf);
    if (strcmp(cp, "exit") == 0)
        exit(0);
    return cp;

}

void int_handler(int signum)
{

    numargs= 0;
    printf("\nArg[%d]? ", numargs);
    fflush(stdout);
}